	//////////////////////////////////////
	//                                  //
	//             anim.js              // 
	//                                  //
	//////////////////////////////////////
	
	////////////////////////////////////
	//   Button Animation Functions   //
	////////////////////////////////////
	// Below are the functions used   //
	// to pulsate certain buttons on  //
	// the toolbar. These functions   //
	// get called by a timer event    //
	// that is instantiated when      //
	// entering an audio page, a      //
	// video page, or a page with a   //
	// more box.                      //
	////////////////////////////////////

	function videoPulse()
	{
		if (vidPulse)
		{
			vidPulse = false;
			theVideoButton.src = imageArray[VIDEO_IMG].src;
		}
		else
		{
			vidPulse = true;
			theVideoButton.src = imageArray[VIDEO_IMG + 1].src;
		}
	}
	
	function morePulse()
	{
		if (morPulse)
		{
			morPulse = false;
			theMoreButton.src = imageArray[MORE_IMG].src;
		}
		else
		{
			morPulse = true;
			theMoreButton.src = imageArray[MORE_IMG + 1].src;
		}
	}
	
	function audioPulse()
	{
		if (audPulse)
		{
			audPulse = false;
			theAudioButton.src = imageArray[AUDIO_IMG].src;
		}
		else
		{
			audPulse = true;
			theAudioButton.src = imageArray[AUDIO_IMG + 1].src;
		}
	}
	
	
	//////////////////////////////////
	//   Button Rollover Routines   //
	//////////////////////////////////
	// Below are the button         //
	// mouseOver, mouseDown,        //
	// mouseUp and mouseOut         //
	// graphic switching            //
	// functions.                   //
	//                              //
	// Each function can be         //
	// called in one of two ways:   //
	//                              //
	// 1) with the image reference  //
	// and the index base for the   //
	// array named imageArray that  //
	// holds the button graphics.   //
	//                              //
	// 2) with the image reference, //
	// a reference to the array     //
	// which holds the button       //
	// graphics, the index base for //
	// the graphics array, and a    //
	// comma separated list of      //
	// boolean expressions.  (The   //
	// graphics switch will only be //
	// performed if all of the      //
	// boolean expressions evaluate //
	// to true.                     //
	//////////////////////////////////
	
	function mOver(imgRef, arrayRef, imgBase)
	{
		var length = mOver.arguments.length;

		if (length == 2)
		{
			imgBase = mOver.arguments[1];
			arrayRef = imageArray;
		}
				
		for (var i=3; i < length; i++)
			if (!mOver.arguments[i]) return;
		
		imgRef.src=arrayRef[imgBase+1].src;
	}

	function mDown(imgRef, arrayRef, imgBase)
	{
		var length = mDown.arguments.length;

		if (length == 2)
		{
			imgBase = mDown.arguments[1];
			arrayRef = imageArray;
		}
		
		for (var i=3; i < length; i++)
			if (!mDown.arguments[i]) return;
						
		imgRef.src=arrayRef[imgBase+2].src;
	}

	function mUp(imgRef, arrayRef, imgBase)
	{
		var length = mUp.arguments.length;

		if (length == 2)
		{
			imgBase = mUp.arguments[1];
			arrayRef = imageArray;
		}
		
		for (var i=3; i < length; i++)
			if (!mUp.arguments[i]) return;
		
		imgRef.src=arrayRef[imgBase+1].src;
	}

	function mOut(imgRef, arrayRef, imgBase)
	{
		var length = mOut.arguments.length;

		if (length == 2)
		{
			imgBase = mOut.arguments[1];
			arrayRef = imageArray;
		}
		
		for (var i=3; i < length; i++)
			if (!mOut.arguments[i]) return;
		
		imgRef.src=arrayRef[imgBase].src;
	}
	
	//////////////////////////////////////////
	// A more 'user friendly' image swapper //
	//////////////////////////////////////////
	// Swaps the button image (objRef) with the
	// image specified (imgRef).
	function swap(objRef, imgRef)
	{
		for (var i=2;i<swap.arguments.length;i++)
			if (!swap.arguments[i]) return;
			
		objRef.src = imgRef.src;
	}
	
	//////////////////////////////////////////////
	//       Frame Animation Functions          //
	//////////////////////////////////////////////
	// Below are the functions used to          //
	// create and kill frame animations.        //
	// The user program calls createAnimation() //
	// to initiate an animated sequence for     //
	// the specified image, and killAnimation() //
	// is called to kill the animation.         //
	//////////////////////////////////////////////
	
	var animArray = new Array();
	
	// createAnimation() creates and adds an animation
	// to the animArray.
	function createFrameAnimation(imgRef, arrayRef, delay, iterations)
	{		
		var id;
		var tempName = imgRef;
		
		if (createFrameAnimation.arguments.length < 4) 
		{
			iterations = -1;
		}
		else
		{
			if (iterations < 1)
			{
				alert("Error in call to createAnimation():\niterations must be greater than 0.");
				return null;
			}
		}
		
		if (typeof imgRef == "string")
		{
			imgRef = getImageRef(imgRef);
			if (imgRef == null)
			{
				alert("Error in call to createAnimation()\Cannot find image, " + tempName + ".");
				return;
			}
		}
	  
		animArray[animArray.length] = new createAnimObj(imgRef, arrayRef, iterations);
		id = setInterval("animator(" + (animArray.length-1) + ");",delay);
		animArray[animArray.length - 1].timerId = id;
		
		return id;
	}
	
	// killAnimation() kills the animation
	// with the specified timerId. This function
	// is designed to work only with animations
	// created with a call to createAnimation.
	function killAnimation(timerId)
	{
		clearInterval(timerId);
	}
	
	// animObject constructor.
	// An animObject holds information
	// about each individual animation.
	function createAnimObj(imgRef, arrayRef, iter)
	{
		this.imgRef = imgRef;
		this.arrayRef = arrayRef;
		this. numFrames = arrayRef.length;
		this.currIndex = -1;
		this.iterations = iter;
		this.timerId = -1;
		
		return this;
	}
	
	// animator() is the function which handles
	// swapping the images in the animation
	// sequence. It is called by the timer
	// which gets created in the user call to
	// createAnimation().
	function animator(animIndex)
	{
		var it = animArray[animIndex];
		it.currIndex++;

		if (it.currIndex == it.numFrames)
		{
			it.iterations--;
			if (it.iterations == 0) 
			{
				killAnimation(it.timerId);
				return;
			}
			it.currIndex = 0;
		}
		
		it.imgRef.src = it.arrayRef[it.currIndex].src;
	}
	
	/////////////////////
	// Path Animations //
	/////////////////////
	
	 
	//PathEvent()
	//
	//Constructor for the PathEvent object.  This object
	//is used by the PathAnimation object to designate
	//points on the screen where a path animation is to visit.
	//Takes four parameters:
	//integer x: x coordinate for the layer's destination.
	//integer y: y coordinate for the layer's destination.
	//integer t: number of milliseconds this event is to take.
	//string c: javascript code that is to be called
	//          upon arrival at the destination point.
	function PathEvent(x,y,t,c)
	{
		if (PathEvent.arguments.length != 4)
		{ 
			alert("Error:  Wrong number of arguments in call to PathEvent(x,y,time,command)!");
			return null;
		}
	
		this.position = new Position(x,y);
		this.timer = t;
		this.command = c;
		return this;
	}
	
	//MAX_ANIMS_PER_SEC is a constant that is defined
	//that determines the maximum number of animations
	//that can reasonably be drawn in a second.  If the
	//animations are happening too slowly, then MAX_ANIMS_PER_SEC
	//should probably be lowered.
	var MAX_ANIMS_PER_SEC = 19;

	//PathAnimation::PathAnimation()
	//
	//Constructor for the PathAnimate object.
	//Takes four parameters:
	//integer x: starting x position of layer to animate.
	//integer y: starting y position of layer to animate.
	//Object lr: Reference to the layer to be animated.
	//string  n: Name of the instance variable being
	//           created with this call to PathAnimation().
	function PathAnimation(x,y,lr,n)
	{  
		//Check to make sure the right number of arguments
		//are supplied.
		if (PathAnimation.arguments.length != 4)
		{
			alert("Error:  Wrong number of arguments in call to PathAnimation(x,y,layerRef,name)!");
			return null;
		}
	
		//Reference to the layer to be animated.
		if (typeof lr == "string")
		{
			lr = getLayerRef(lr);
		}
		this.layerRef = lr;

		//Position object to keep track of layer's current position.
		this.position = new Position(getLayerX(this.layerRef),getLayerY(this.layerRef));

		//Position object to keep track of layer's starting position.
		this.startPosition = new Position(x,y);

		//Array of PathEvent objects.
		this.pathEvents = new Array();
		
		//Variable to hold the identifier name for
		//the current instance.
		this.objName = n;

		//Assignments for member functions.
		this.playAnimation = UserPlay;
		this.play1 = PlayAnimation;
		this.killAnimation = KillAnimation;
		this.initAnimation = InitAnimation;
		this.addPathEvent = AddPathEvent;
		this.pauseAnimation = PauseAnimation;
		this.anim = Anim;
		 
		///////////////////////////////////////////////////
		//State variables used during animation sequence.//
		///////////////////////////////////////////////////
		
		//Variable to keep track of currently active
		//PathEvent object.
		this.index = 0;
		
		//Variable to track currently active animation timer.
		this.timerId = null;
		
		//Variable to track current step within
		//the currently active PathEvent sequence.
		this.step = 0;
		
		//Variable to keep track of the number of steps in 
		//the currently active PAthEvent sequence.
		this.steps = null;

		//Array that holds all of the points in the
		//currently active PathEvent sequence.
		this.points = null;
		
		//Variable to hold the number of points
		//to be skipped in the currently active 
		//PathEvent sequence.
		this.skip = null;
		
		//Variable to keep track of the timer interval
		//to be used for the currently active PathEvent sequence.
		this.timeInterval = null;
		
		//Flag to keep track of whether or not a
		//PathEvent is currently suspended.
		this.suspended = false;
		
		//Flag to keep track of whether or not a
		//PathEvent is currently running.
		this.running = false;
		
		return this;
	} 
	
	function UserPlay()
	{
		if (this.running) 
		{
			return;
		}
		else 
		{
			this.running = true;
			this.play1();
		}
	}
	
	//PathAnimation::AddPathEvent()
	//
	//Member function of the PathAnimate object
	//which adds a PathEvent object to the
	//this.pathEvents[] array.
	//Takes four parameters:
	//integer x: x coordinate for the layer's destination.
	//integer y: y coordinate for the layer's destination.
	//integer t: number of milliseconds this event is to take.
	//string command: javascript code that is to be called
	//                upon arrival at the destination point.
	function AddPathEvent(x,y,t,command)
	{
		if (AddPathEvent.arguments.length != 4)
		{
			alert("Error:  Wrong number of arguments in call to AddPathEvent(x,y,time,command)!");
			return null;
		}
	
		this.pathEvents[this.pathEvents.length] = new PathEvent(x,y,t,command);
	}
	
	//PathAnimation::Anim()
	//
	//Member function of the PathAnimate object
	//which gets called via a timer, and does the actual
	//moving of the layer.
	function Anim() 
	{
		//Check to see if there are steps left in
		//the animation sequence.  If there are then
		//go ahead and move the layer, and increment
		//the this.step variable.
		if (this.step < this.steps-1)
		{
			this.position.setX(this.points[this.step].getX());
			this.position.setY(this.points[this.step].getY());
			moveLayer(this.layerRef,this.position.getX(),this.position.getY());
			this.step = this.step + 1 + this.skip;
		}
		else
		{
			//There are no steps left in the current
			//PathEvent, so move the layer to this 
			//PathEvent's fincal position, kill the
			//timer, increment this.index so it points
			//to the next PathEvent in the this.PathEvents[]
			//array, execute the current PathEvent's
			//javascript command string, and start
			//the next PathEvent if there is one.
			clearInterval(this.timerId);
			this.position.setX(this.pathEvents[this.index].position.getX());
			this.position.setY(this.pathEvents[this.index].position.getY());
			moveLayer(this.layerRef,this.position.getX(),this.position.getY());
			eval(this.pathEvents[this.index].command);
			this.index++; 
			if (this.index < this.pathEvents.length)
			{
				 this.play1();
			}		
			else
			{
				this.index = 0;
				this.suspended = false;
				this.running = false;
			}	
		}
	}
	
	//PathAnimation::PlayAnimation()
	//
	//Member function of the PathAnimate object
	//which calculates the path of the next
	//PathEvent, designated by the this.index variable,
	//stores all points along the path in an array,
	//this.points[], determines if we are exceeding the
	//maximum number of animations per second allowed and
	//adjusts the this.skip variable accordingly, calculates
	//the time interval between calls to 
	//PathAnimation::Anim, and finally sets the
	//interval for the animation to begin.
	function PlayAnimation()
	{ 
		//If there is already an animation running
		//just go ahead and start it back up.
		if (this.suspended)
		{ 
			this.suspended = false;
			clearInterval(this.timerId);
			this.timerId = setInterval(this.objName+".anim()",this.timeInterval);
			return;
		}
		
		var x1,y1,x2,y2,tempX,tempY,slope;
		var xSign, ySign;
		var timeInterval;
		
		this.step = 0;  
		this.position.setX(getLayerX(this.layerRef));
		this.position.setY(getLayerY(this.layerRef));
		
		//Convert to cartesian coordinates so
		//I can think straight.
		x1 = this.position.getX();
		y1 = 0 - this.position.getY();
		x2 = this.pathEvents[this.index].position.getX();
		y2 = 0 - this.pathEvents[this.index].position.getY();
		//Calculate slope for current pathEvent.
		slope = (y1-y2)/(x1-x2);
		
		//Calculate directional signs for x and y movements.
		//(whether x/y increase or decrease from point1 to point2.
		if (y1 < y2)
		{
			ySign = 1;
		}
		else
		{
			ySign = -1;
		}
		
		if (x1 < x2)
		{
			xSign = 1;
		}
		else
		{
			xSign = -1;
		}
		
		
		//Calculate number of unique points on the path.
		//Then create an array of all points on the path.
		if (!isFinite(slope) || (Math.abs(slope) >= 1))
		{	
			this.steps = Math.abs(y1-y2);
			this.points = new Array();
			for (var i=0;i<this.steps;i++)
			{ 
				if (!isFinite(slope))
				{
					tempX = x1;
				}
				else
				{
					tempX = x1 + xSign*Math.round((i+1)/Math.abs(slope));
				} 
				//The negative sign on the y parameter is to 
				//convert from cartesian to screen coordinates.
				this.points[i] = new Position(tempX,-(y1+ySign*(i+1)));
			}

		}
		else
		{
			this.steps = Math.abs(x1-x2);
			this.points = new Array();
			for (var i=0;i<this.steps;i++)
			{  
				//The negative sign on the y parameter is to 
				//convert from cartesian to screen coordinates.
				this.points[i] = new Position(x1+xSign*(i+1),-(y1 + ySign*Math.round((i+1)*Math.abs(slope))));
			}
		}
		
		//Check for 0 step movements
		if (this.steps == 0)
		{	this.steps = 1;
			this.points = new Array();
			this.points[0] = new Position(x2,-y2);
		}

		//Check to make sure we are not exceeding the maximum
		//predefined pixels per second limit.  If we are then
		//we need to calculate this.skip.  This.skip is the number
		//of points on the line that will be skipped in between
		//each animating step.
		if ( (this.points.length/(this.pathEvents[this.index].timer/1000)) > MAX_ANIMS_PER_SEC )
		{  
			var stepsToRemove;
			stepsToRemove = Math.round(this.points.length - ((this.pathEvents[this.index].timer/1000)*MAX_ANIMS_PER_SEC));
			this.skip = Math.round((this.points.length/(this.points.length-stepsToRemove))-1);
		}
		else
		{
			this.skip = 0;
		}		

		//We now need to calculate the time interval that is
		//going to be used according to the PathEvents timer
		//property and the number of steps.
		this.timeInterval = Math.round(this.pathEvents[this.index].timer/this.steps);
		clearInterval(this.timerId);
		this.timerId = setInterval(this.objName+".anim()",this.timeInterval);
	}
	
	//PathAnimation::InitAnimation()
	//
	//Member function of the PathAnimate object
	//which initializes the animation to its
	//originally designated state.
	function InitAnimation()
	{
		clearInterval(this.timerId);
		this.index = 0;
		this.position.setX(this.startPosition.getX());
		this.position.setY(this.startPosition.getY());
		moveLayer(this.layerRef,this.startPosition.getX(),this.startPosition.getY());
		this.running = false;
		this.suspended = false;
	}
	
	//PathAnimation::KillAnimation()
	//
	//Member function of the PathAnimate object
	//which kills the current animation sequesnce
	//leaving the layer where it was last placed.
	function KillAnimation()
	{
		this.initAnimation();
	}
	
	function PauseAnimation()
	{
		if (!this.suspended && this.running)
		{
			clearInterval(this.timerId);
			this.suspended = true;
			this.running = false;
		}
	}
	
